package yang.yu.sunny.infra.elasticsearch;

import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.elasticsearch.action.delete.DeleteResponse;
import org.elasticsearch.action.get.GetResponse;
import org.elasticsearch.action.index.IndexResponse;
import org.elasticsearch.action.search.SearchResponse;
import org.elasticsearch.action.search.SearchType;
import org.elasticsearch.client.Client;
import org.elasticsearch.index.query.QueryBuilder;
import org.elasticsearch.index.query.QueryBuilders;
import org.elasticsearch.search.SearchHit;
import yang.yu.sunny.domain.AbstractEntity;

import java.io.IOException;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;

/**
 * Created by yyang on 16/4/11.
 */
public abstract class AbstractSearcher<T extends AbstractEntity> {

    protected static final String INDEX = "mes";

    private Client client;

    private ObjectMapper objectMapper = new ObjectMapper();

    public AbstractSearcher(Client client) {
        this.client = client;
    }

    protected abstract String getType();

    protected abstract Class<T> getDocClass();


    public T get(Long id) {
        GetResponse response = client
                .prepareGet(INDEX, getType(), id.toString())
                .get();
        try {
            return objectMapper.readValue(response.getSourceAsBytes(), getDocClass());
        } catch (IOException e) {
            e.printStackTrace();
            return null;
        }
    }

    public List<T> findById(Collection<Long> ids) {
        return findByQuery(QueryBuilders.termsQuery("id", ids));
    }

    public List<T> findByName(String name) {
        return findByQuery(QueryBuilders.matchQuery("name", name));
    }

    private List<T> findByQuery(QueryBuilder builder) {
        SearchResponse response = client
                .prepareSearch(INDEX)
                .setTypes(getType())
                .setSearchType(SearchType.QUERY_AND_FETCH)
                .setQuery(builder)
                //.setFrom(0).setSize(60).setExplain(true)
                .execute()
                .actionGet();
        List<T> results = new ArrayList<>();
        for (SearchHit hit : response.getHits().getHits()) {
            try {
                T entity = objectMapper.readValue(hit.source(), getDocClass());
                results.add(entity);
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
        return results;
    }


    public void create(T entity) {
        try {
            IndexResponse response = client
                    .prepareIndex(INDEX, getType(), entity.getId().toString())
                    .setSource(objectMapper.writeValueAsBytes(entity))
                    .get();
        } catch (JsonProcessingException e) {
            e.printStackTrace();
        }
    }

    public void update(T entity) {
        remove(entity.getId());
        create(entity);
    }

    public void remove(Long id) {
        DeleteResponse response = client.prepareDelete(INDEX, getType(), id.toString()).get();
    }

}
